package org.system.core.service.system;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.system.core.annotation.DataScope;
import org.system.core.common.Constants;
import org.system.core.domain.entity.SysDept;
import org.system.core.domain.entity.SysRole;
import org.system.core.domain.entity.SysUser;
import org.system.core.domain.model.TreeSelect;
import org.system.core.exception.AuthorityException;
import org.system.core.exception.ServiceException;
import org.system.core.mapper.system.SysDeptMapper;
import org.system.core.mapper.system.SysRoleMapper;
import org.system.core.utils.*;
import org.system.core.utils.spring.SpringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author baoRoot
 */
@Service
public class SysDeptService {

    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private SysRoleMapper sysRoleMapper;

    @DataScope(deptAlias = "d")
    public List<SysDept> selectDeptList(SysDept dept) {
        return sysDeptMapper.selectDeptList(dept);
    }

    public SysDept selectDeptById(Long deptId) {
        return sysDeptMapper.selectDeptById(deptId);
    }

    /**
     * 校验权限
     * @param deptId
     */
    public void checkDeptDataScope(Long deptId) {
        if (deptId == null || deptId <= 0) {
            throw new ServiceException(MessageUtils.message("system.dept.no_id"));
        }
        if (!SysUser.isAdmin(SecurityUtils.getUserId())) {
            SysDept dept = new SysDept();
            dept.setDeptId(deptId);
            List<SysDept> deptList = SpringUtils.getAopProxy(this).selectDeptList(dept);
            if (StringUtil.isEmpty(deptList)) {
                throw new AuthorityException(MessageUtils.message("system.user.no_permission"));
            }
        }
    }

    public void deleteDept(Long deptId) {
        checkDeptDataScope(deptId);
        if (sysDeptMapper.hasChildByDeptId(deptId) > 0) {
            throw new ServiceException(MessageUtils.message("system.dept.child_of_existence"));
        }
        if (sysDeptMapper.checkDeptExistUser(deptId) > 0) {
            throw new ServiceException(MessageUtils.message("system.dept.existing_user"));
        }
        if (sysDeptMapper.deleteDeptById(deptId) <= 0) {
            throw new ServiceException(MessageUtils.message("system.monitor.delete_error"));
        }
    }

    /**
     * 校验名称唯一性
     * @param dept
     * @return
     */
    public boolean checkDeptNameUnique(SysDept dept) {
        Long deptId = StringUtil.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();
        SysDept info = sysDeptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId());
        return StringUtil.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue();
    }

    public void insertDept(SysDept dept) {
        if (checkDeptNameUnique(dept)) {
            throw new ServiceException("部门【" + dept.getDeptName() + "】已存在");
        }
        dept.setCreateBy(SecurityUtils.getUsername());
        SysDept sysDept = sysDeptMapper.selectDeptById(dept.getParentId());
        if (!Constants.DEPT_NORMAL.equals(sysDept.getStatus())) {
            throw new ServiceException(MessageUtils.message("system.dept.status_off"));
        }
        dept.setAncestors(sysDept.getAncestors() + "," + dept.getParentId());
        if (sysDeptMapper.insertDept(dept) <= 0) {
            throw new ServiceException(MessageUtils.message("system.monitor.add_error"));
        }
    }

    public void updateDept(SysDept dept) {
        Long deptId = dept.getDeptId();
        checkDeptDataScope(deptId);
        if (checkDeptNameUnique(dept)) {
            throw new ServiceException("部门【" + dept.getDeptName() + "】已存在");
        }
        if (dept.getParentId().equals((deptId))) {
           throw new ServiceException(MessageUtils.message("system.dept.superiors_error"));
        }
        if (StringUtil.equals(Constants.DEPT_DISABLE, dept.getStatus()) && selectNormalChildrenDeptById(deptId) > 0) {
            throw new ServiceException(MessageUtils.message("system.dept.status_error"));
        }
        dept.setUpdateBy(SecurityUtils.getUsername());
        SysDept newParentDept = sysDeptMapper.selectDeptById(dept.getParentId());
        SysDept oldDept = sysDeptMapper.selectDeptById(dept.getDeptId());
        if(StringUtil.isNotNull(newParentDept) && StringUtil.isNotNull(oldDept)) {
            String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId();
            String oldAncestors = oldDept.getAncestors();
            dept.setAncestors(newAncestors);
            updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
        }
        if (Constants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtil.isNotEmpty(dept.getAncestors()) && !StringUtil.equals("0", dept.getAncestors())) {
            // 如果该部门是启用状态，则启用该部门的所有上级部门
            updateParentDeptStatusNormal(dept);
        }
        if (sysDeptMapper.updateDept(dept) <= 0) {
            throw new ServiceException(MessageUtils.message("system.monitor.update_error"));
        }
    }

    private void updateParentDeptStatusNormal(SysDept dept) {
        String ancestors = dept.getAncestors();
        Long[] deptIds = ConvertUtils.toLongArray(ancestors);
        sysDeptMapper.updateDeptStatusNormal(deptIds);
    }

    /**
     * 修改子元素关系
     * @param deptId
     * @param newAncestors
     * @param oldAncestors
     */
    public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) {
        List<SysDept> children = sysDeptMapper.selectChildrenDeptById(deptId);
        for (SysDept child : children) {
            child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
        }
        if (!children.isEmpty()) {
            sysDeptMapper.updateDeptChildren(children);
        }
    }

    public int selectNormalChildrenDeptById(Long deptId) {
        return sysDeptMapper.selectNormalChildrenDeptById(deptId);
    }

    public List<TreeSelect> selectDeptTreeList(SysDept dept) {
        List<SysDept> deptList = SpringUtils.getAopProxy(this).selectDeptList(dept);
        return buildDeptTreeSelect(deptList);
    }

    private List<SysDept> getChildList(List<SysDept> list, SysDept t) {
        List<SysDept> tlist = new ArrayList<>();
        for (SysDept n : list) {
            if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    private boolean hasChild(List<SysDept> list, SysDept t) {
        return !getChildList(list, t).isEmpty();
    }

    private void recursionFn(List<SysDept> list, SysDept t) {
        // 得到子节点列表
        List<SysDept> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysDept tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    public List<SysDept> buildDeptTree(List<SysDept> depts) {
        List<SysDept> returnList = new ArrayList<>();
        List<Long> tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
        for (SysDept dept : depts) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getParentId())) {
                recursionFn(depts, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty()) {
            returnList = depts;
        }
        return returnList;
    }

    public List<TreeSelect> buildDeptTreeSelect(List<SysDept> list) {
        List<SysDept> deptTrees = buildDeptTree(list);
        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    public List<Long> selectDeptListByRoleId(Long roleId) {
        SysRole role = sysRoleMapper.selectRoleById(roleId);
        return sysDeptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());
    }

}
